import selectors
import socket
import threading
import logging


class ChatServer:
    def __init__(self,ip='127.0.0.1',port=9999):
        self.addr = ip,port
        self.sock = socket.socket()
        self.sock.setblocking(False)
        self.event = threading.Event()
        self.selector = selectors.DefaultSelector()

    def start(self):
        self.sock.bind(self.addr)
        self.sock.listen()
        key = self.selector.register(self.sock,selectors.EVENT_READ,self.accept)

        threading.Thread(target=self.select,name='select').start()

    def select(self):
        with self.selector:
            while not self.event.is_set():
                events = self.selector.select(0.5)
                for key,mask in events:
                    key.data(key.fileobj,mask)

    def accept(self,server:socket.socket,mask):
        conn,raddr = server.accept()
        conn.setblocking(False)
        logging.info("New client {} accepted. fd = {}".format(raddr,conn.fileno()))
        key = self.selector.register(conn,selectors.EVENT_READ,self.recv)

    def recv(self,conn:socket.socket,mask):
        data = conn.recv(1024).strip()
        if data == b'quit' or data == b'':
            self.selector.unregister(conn)
            conn.close()
            return
        msg = "Your msg={}".format(data.decode()).encode()
        logging.info(msg)
        for key in self.selector.get_map().values():
            if key.data == self.recv:
                key.fileobj.send(msg)

    def stop(self):
        self.event.set()

if __name__ == '__main__':
    cs = ChatServer()
    cs.start()
    while True:
        cmd = input('>>').strip()
        if cmd == 'quit':
            cs.stop()
            break
        print(*cs.selector.get_map().values())